package com.llyb.tingshu.payment.service.impl;

import com.llyb.tingshu.account.client.RechargeInfoFeignClient;
import com.llyb.tingshu.common.constant.SystemConstant;
import com.llyb.tingshu.common.execption.GuiguException;
import com.llyb.tingshu.common.result.Result;
import com.llyb.tingshu.model.account.RechargeInfo;
import com.llyb.tingshu.model.order.OrderInfo;
import com.llyb.tingshu.model.payment.PaymentInfo;
import com.llyb.tingshu.order.client.OrderInfoFeignClient;
import com.llyb.tingshu.payment.config.WxPayV3Config;
import com.llyb.tingshu.payment.service.PaymentInfoService;
import com.llyb.tingshu.payment.service.WxPayService;
import com.llyb.tingshu.payment.util.PayUtil;
import com.llyb.tingshu.user.client.UserInfoFeignClient;
import com.llyb.tingshu.vo.user.UserInfoVo;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

	@Autowired
	private PaymentInfoService paymentInfoService;

	@Resource
	private RechargeInfoFeignClient rechargeInfoFeignClient;

	@Resource
	private OrderInfoFeignClient orderInfoFeignClient;

	@Resource
	private UserInfoFeignClient userInfoFeignClient;

	@Autowired
	private WxPayV3Config wxPayV3Config;

	@Autowired
	private RSAAutoCertificateConfig config;

	@Override
	public Map createJsapi(String paymentType, String orderNo, Long userId) {

		BigDecimal totalAmount = new BigDecimal("0.0");
		// 1. 生成支付记录
		/**
		 * 1.1 判断支付类型
		 * 	1.1.1 订单支付
		 * 	1.1.2 充值
		 */
		if (SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType)) {
			// 远程调用订单获取金额
			Result<OrderInfo> orderInfoR = orderInfoFeignClient.getOrderInfo(orderNo);
			Assert.notNull(orderInfoR,"远程调用获取订单信息失败");
			OrderInfo orderInfo = orderInfoR.getData();
			Assert.notNull(orderInfo,"获取订单信息为空");

			if (!orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_UNPAID) || orderInfo == null){
				return new HashMap();
			}
			totalAmount = orderInfo.getOrderAmount();

		}else {
			// 远程调用充值获取金额
			Result<RechargeInfo> rechargeInfoR = rechargeInfoFeignClient.getRechargeInfo(orderNo);
			Assert.notNull(rechargeInfoR,"远程调用获取充值信息失败");
			RechargeInfo rechargeInfo = rechargeInfoR.getData();
			Assert.notNull(rechargeInfo,"获取充值信息为空");
			totalAmount = rechargeInfo.getRechargeAmount();
		}
		paymentInfoService.savePaymentInfo(paymentType, orderNo, userId, totalAmount);

		// 2. 生成交易界面
		JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();

		// 跟之前下单示例一样，填充预下单参数
		PrepayRequest request = new PrepayRequest();

		Amount amount = new Amount();
		amount.setTotal(1);
		request.setAmount(amount);
		request.setAppid(wxPayV3Config.getAppid());
		request.setMchid(wxPayV3Config.getMerchantId());
		request.setDescription("测试商品标题");
		request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
		//  在微信内部：订单商户号叫out_trade_no; 在我们平台叫：order_no;
		request.setOutTradeNo(orderNo);

		Payer payer = new Payer();
		//  获取用户的openid;
		Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
		Assert.notNull(userInfoVoResult, "查询用户信息失败");
		UserInfoVo userInfoVo = userInfoVoResult.getData();
		Assert.notNull(userInfoVo, "查询用户信息失败");
		payer.setOpenid(userInfoVo.getWxOpenId());
		request.setPayer(payer);
		//  设置订单过期时间；
		//  request.setTimeExpire(System.currentTimeMillis() + 1000 * 60 * 10);

		PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);

		Map<String, Object> map = new HashMap<>();

		//  赋值：
		map.put("timeStamp", response.getTimeStamp()); // 时间戳
		map.put("nonceStr", response.getNonceStr());   // 随机字符串
		map.put("package", response.getPackageVal());  // 订单详情扩展字符串
		map.put("signType", response.getSignType());   // 签名方式
		map.put("paySign", response.getPaySign());     // 签名

		return map;
	}

	@Override
	public Transaction queryPayStatus(String orderNo) {
		QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
		request.setMchid(wxPayV3Config.getMerchantId());
		request.setOutTradeNo(orderNo);

		try {
			//  构建service对象；
			JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
			Transaction result = service.queryOrderByOutTradeNo(request);
			System.out.println(result.getTradeState());
			//  返回数据
			return result;
		} catch (ServiceException e) {
			// API返回失败, 例如ORDER_NOT_EXISTS
			System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
			System.out.printf("reponse body=[%s]\n", e.getResponseBody());
		}

		return null;
	}

	@Override
	public Map<String, Object> createNative(String paymentType, String orderNo, Long userId) {
		try {

			BigDecimal totalAmount = new BigDecimal("0.0");
			// 1. 生成支付记录
			/**
			 * 1.1 判断支付类型
			 * 	1.1.1 订单支付
			 * 	1.1.2 充值
			 */
			if (SystemConstant.PAYMENT_TYPE_ORDER.equals(paymentType)) {
				// 远程调用订单获取金额
				Result<OrderInfo> orderInfoR = orderInfoFeignClient.getOrderInfo(orderNo);
				Assert.notNull(orderInfoR,"远程调用获取订单信息失败");
				OrderInfo orderInfo = orderInfoR.getData();
				Assert.notNull(orderInfo,"获取订单信息为空");

				if (!orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_UNPAID) || orderInfo == null){
					return new HashMap();
				}
				totalAmount = orderInfo.getOrderAmount();

			}else {
				// 远程调用充值获取金额
				Result<RechargeInfo> rechargeInfoR = rechargeInfoFeignClient.getRechargeInfo(orderNo);
				Assert.notNull(rechargeInfoR,"远程调用获取充值信息失败");
				RechargeInfo rechargeInfo = rechargeInfoR.getData();
				Assert.notNull(rechargeInfo,"获取充值信息为空");
				totalAmount = rechargeInfo.getRechargeAmount();
			}

			//保存支付记录
			paymentInfoService.savePaymentInfo(paymentType, orderNo,userId,totalAmount);

			// 构建service
			NativePayService service = new NativePayService.Builder().config(config).build();
			// request.setXxx(val)设置所需参数，具体参数可见Request定义
			com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest request = new com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest();
			com.wechat.pay.java.service.payments.nativepay.model.Amount amount = new com.wechat.pay.java.service.payments.nativepay.model.Amount();
			amount.setTotal(1);
			request.setAmount(amount);
			request.setAppid(wxPayV3Config.getAppid());
			request.setMchid(wxPayV3Config.getMerchantId());
			request.setDescription("测试商品标题");
			request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
			request.setOutTradeNo(orderNo);

			// 调用下单方法，得到应答
			com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse response = service.prepay(request);
			// 使用微信扫描 code_url 对应的二维码，即可体验Native支付
			System.out.println(response.getCodeUrl());

			Map result = new HashMap<>();
			result.put("codeUrl", response.getCodeUrl());
			return result;
		} catch (ServiceException e) {
			e.printStackTrace();
			throw new GuiguException( 201, e.getErrorMessage());
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			throw new GuiguException( 201, "订单号不存在");
		} catch (Exception e) {
			e.printStackTrace();
			throw new GuiguException( 201, "微信下单异常");
		}
	}

	@Override
	public void wxNotify(HttpServletRequest request) {
		String wechatPaySerial = request.getHeader("Wechatpay-Serial");
		String nonce = request.getHeader("Wechatpay-Nonce");
		String timestamp = request.getHeader("Wechatpay-Timestamp");
		String signature = request.getHeader("Wechatpay-Signature");
		// 调用工具类来获取请求体数据
		String requestBody = PayUtil.readData(request);

		//2.构造 RequestParam
		RequestParam requestParam = new RequestParam.Builder()
				.serialNumber(wechatPaySerial)
				.nonce(nonce)
				.signature(signature)
				.timestamp(timestamp)
				.body(requestBody)
				.build();


		//3.初始化 NotificationParser
		NotificationParser parser = new NotificationParser(config);

		//4.以支付通知回调为例，验签、解密并转换成 Transaction
		Transaction transaction = parser.parse(requestParam, Transaction.class);

		if(null != transaction && transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
			// 5.处理支付业务
			paymentInfoService.updatePaymentStatus(transaction);
		}
	}


}
